#pragma once
#include <Windows.h>
#include <allocators>

#ifdef max
#undef max
#endif

// this custom allocator is useful for keeping DirectX::XMVECTOR numbers
// properly aligned inside the std::vector

template <typename T>
class AlignedAllocator
{
public:
public:
	//    typedefs
	typedef T value_type;
	typedef value_type* pointer;
	typedef const value_type* const_pointer;
	typedef value_type& reference;
	typedef const value_type& const_reference;
	typedef std::size_t size_type;
	typedef std::ptrdiff_t difference_type;

public:
	//    convert an AlignedAllocator<T> to AlignedAllocator<U>
	template<typename U>
	struct rebind {
		typedef AlignedAllocator<U> other;
	};


public:
	inline explicit AlignedAllocator() {};
	inline ~AlignedAllocator() {};
	inline explicit AlignedAllocator(AlignedAllocator const&) {};
	template<typename U>
	inline explicit AlignedAllocator(AlignedAllocator<U> const&) {}

	//    address
	inline pointer address(reference r) { return &r; }
	inline const_pointer address(const_reference r) { return &r; }

	//    memory allocation
	pointer allocate(size_type cnt, const void* hint = 0)
	{
		int alignmentInBytes = ((sizeof(T) ^ (sizeof(T) - 1)) + 1) >> 1;

		return reinterpret_cast<pointer>(_aligned_malloc(
			cnt * sizeof(T), alignmentInBytes));
	}

	void deallocate(pointer p, size_type)
	{
		if (p)
		{
			_aligned_free(p);
		}
	}

	//    size
	inline size_type max_size() const {
		return (std::numeric_limits<size_type>::max() / sizeof(T)) - 1;
	}

	//    construction/destruction
	inline void construct(pointer p, const T& t) { new(p)T(t); }
	inline void destroy(pointer p) { p->~T(); }

	inline bool operator==(AlignedAllocator const&) { return true; }
	inline bool operator!=(AlignedAllocator const& a) { return !operator==(a); }
};
